#include "stdafx.h"
#include "ncLog.h"

#include <WinSock2.h>
#include <stdarg.h> 
#include <stdio.h>
#include "debug.h"

#pragma comment(lib , "Ws2_32") 

namespace Debug
{
	static SOCKET wsa_socket=INVALID_SOCKET;
	static unsigned short theLogPort;

	// bind the log socket to a specific port. 
	bool ncLog::wsa_bind(unsigned short port) 
	{ 
		SOCKADDR_IN addr; 
		addr.sin_family = AF_INET; 
		addr.sin_port = htons(port); 
		addr.sin_addr.s_addr = htonl(INADDR_ANY); 
		int r=bind(wsa_socket,(sockaddr*)&addr,sizeof(addr)); 
		if (r==0)
		{
			theLogPort = port; 
		}
		return (r==0); 
	} 

	// initialize everything, if the socket isn't open. 
	bool ncLog::wsa_init() 
	{ 
		if (wsa_socket != INVALID_SOCKET)
		{
			return true; 
		}

		WSADATA wd; 
		BOOL bc=true; 
		int r = WSAStartup(MAKEWORD( 2, 2 ), &wd);
		if( r != 0 )
		{
			char buffer[256];
			sprintf_s(buffer, 256, "Failed to init Server. WSAStartup() returned errorcode: %d\n", r);
			OutputDebugStringA(buffer);
			Error();
			return false;
		}
		if ((LOBYTE( wd.wVersion ) != 2) || (HIBYTE( wd.wVersion ) != 2))
		{
			OutputDebugStringA("Failed to init Server. WSAStartup() couldn't find a usable version of winsock.dll\n");
			Error();
			WSACleanup();
			return false;
		}

		wsa_socket=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 
		if (wsa_socket == INVALID_SOCKET)
		{
			char buffer[256];
			sprintf_s(buffer, 256, "Failed to init Server. socket() generated error: %d\n", WSAGetLastError());
			OutputDebugStringA(buffer);
			Error();
			WSACleanup();
			return false; 
		}

		r = setsockopt(wsa_socket, SOL_SOCKET, SO_BROADCAST, (char*)&bc, sizeof(bc)); 
		if (r!=0)
		{
			Error();
			return false;
		}
		if (wsa_bind(9999))
		{
			return true; // bind to default port. 
		}

		Error();
		return false;
	} 

	// can be called externally to select a different port for operations 
	void ncLog::wsa_send(const char *x) 
	{ 
		SOCKADDR_IN sa; 
		sa.sin_family = AF_INET; 
		sa.sin_port = htons(theLogPort); 
		sa.sin_addr.s_addr = htonl(INADDR_BROADCAST); 
		if (SOCKET_ERROR == sendto(wsa_socket,x,strlen(x), 0, (sockaddr*) &sa, sizeof(sa))) 
		{
			OutputDebugStringA("nclog: Send Error\n"); 
		} 
	} 

	// format input, convert to 8-bit and send. 
	void ncLog::log(const wchar_t *fmt, ...) 
	{ 
		va_list vl; 
		va_start(vl,fmt); 
		wchar_t buf[1024]; // to bad CE hasn't got wvnsprintf 
		wvsprintfW(buf,fmt,vl); 
		wsa_init(); 
		char bufOut[512]; 
		WideCharToMultiByte(CP_ACP,0,buf,-1,bufOut,400, NULL, NULL); 
		wsa_send(bufOut); 
	} 
	void ncLog::log(const char *fmt, ...) 
	{ 
		va_list vl; 
		va_start(vl,fmt); 
		char buf[1024];
		vsprintf_s(buf, 1024, fmt, vl); 
		wsa_init(); 
		wsa_send(buf); 
	} 

	void ncLog::Error()
	{
		if (wsa_socket != INVALID_SOCKET)
		{
			closesocket(wsa_socket); 
		}
		char buffer[256];
		sprintf_s(buffer, "nclog: TCP/IP Problem (%d)\n", WSAGetLastError());
		OutputDebugStringA(buffer); 
	}

	// finalize the socket on program termination. 
	struct _nclog_module 
	{ 
		~_nclog_module() 
		{ 
			if (wsa_socket!=INVALID_SOCKET) 
			{ 
				ncLog::log(L"nclog goes down\n"); 
				shutdown(wsa_socket,2); 
				closesocket(wsa_socket); 
			} 
		} 
	}; 

	static _nclog_module module;
}

